_Pragma("once");

#include <malloc.h>
#include <cstring>
#include <cstdint>

#include "MultiPortDevice.h"
#include "LoopGroupInfo.h"
#include "ErrorCode.h"
#include "LoopStatus.h"
#include "HalUtility.h"
#include "AcDetector.h"
#include "LoopControllerConfigInfo.h"

class LoopManager;

class LoopController : public AcDetector {

    friend class LoopManager;

public:
    LoopController(DummyChannel& channel, const ExtendDeviceType& deviceType, const std::string& deviceActknowlege, const LoopSize_t& startIndex = 0, const LoopSize_t& portCount = MDConst::DEFAULT_INTERNAL_LOOP_COUNT);

    /** Default destructor */
    virtual ~LoopController();

    bool initialize() noexcept override;

    void allocStatusMemory();


    /**
     * 根据command修改回路状态（自动操作）
     *
     * @param command
     * @return
     */
    void changeAutoLoopStatus(const LoopStatus* command, const LoopSize_t& length) {
        if (this->mportCount < length) {
            throw BUILD_EXCEPTION(FirmwareError::LOOP_COUNT_NO_MATCH);
        }

        changeAllChannelStatusFunc(command, length);// 执行指令
        copyLoopStatusArray(command, length);
    }



    void changeManualLoopStatus(const LoopStatus* command, const LoopSize_t& length) {
        if (this->mportCount < length) {
            throw BUILD_EXCEPTION(FirmwareError::LOOP_COUNT_NO_MATCH);
        }
        changeAllChannelStatusFunc(command, length);// 执行指令

        const size_t size = std::min(this->mportCount, length);

        for (int i = 0; i < size; ++i) {
            if (LoopStatus::NO_BACKUP_STATUS == mbackupLoopStatusArray[i]) {
                mbackupLoopStatusArray[i] = mloopStatusArray[i];
            }
        }
        std::memcpy(mloopStatusArray, command, size);
    }


    /**
     * 修改手动回路状态 强制修改 即使是手动状态也会被自动状态覆盖
     *
     * @param status  回路状态
     * @param loopNum 回路在回路组中的坐标（第几个）
     * @return
     */
    LoopStatus changeManualLoopStatus(const LoopSize_t& loopNum, const LoopStatus& status) {
        LoopStatus nextManualStatus = status;
        if (LoopStatus::NEXT_MANUAL_STATUS == status) {
            nextManualStatus = computeNextManualStatus(loopNum);
        }

        changeSingleChannelStatusFunc(loopNum, nextManualStatus); // 实际修改回路状态的操作
        if (LoopStatus::NO_BACKUP_STATUS == mbackupLoopStatusArray[loopNum]) {
            mbackupLoopStatusArray[loopNum] = mloopStatusArray[loopNum];
        }
        mloopStatusArray[loopNum] = nextManualStatus;

        //  throw BUILD_EXCEPTION(FirewareError::LOOP_SWITCH_FAILED);
        return nextManualStatus;
    }


    LoopStatus computeNextManualStatus(const LoopSize_t& loopIndex) {
        LoopStatus currentStatus =  mloopStatusArray[loopIndex];
        LoopStatus nextStatus;
        switch (currentStatus) {
        case LoopStatus::MANUAL_OFF:
            nextStatus = LoopStatus::MANUAL_ON;
            break;

        case LoopStatus::MANUAL_ON:
            nextStatus = mbackupLoopStatusArray[loopIndex];
            if (LoopStatus::NO_BACKUP_STATUS == nextStatus) {
                nextStatus = MANUAL_OFF;
            }
            break;

        case LoopStatus::AUTO_OFF:
        case LoopStatus::AUTO_ON:
            nextStatus = LoopStatus::MANUAL_OFF;
            break;

        default:
            nextStatus = LoopStatus::MANUAL_OFF;
            break;
        }

        return nextStatus;
    }


    void copyLoopStatusArray(const LoopStatus* command, const LoopSize_t& length) {
        const size_t size = std::min(this->mportCount, length);
        std::memcpy(mloopStatusArray, command, size);
        std::memset(mbackupLoopStatusArray, LoopStatus::NO_BACKUP_STATUS, size);
    }


    /***
     * 回路控制器实际的控制方法
     *
     * @param command
     * @return
     */
    virtual void changeAllChannelStatusFunc(const LoopStatus* command, const LoopSize_t& length) ;

    /***
     * 回路控制器实际的控制方法
     *
     * @param status
     * @param loopNum 从0开始
     * @return
     */
    virtual  void changeSingleChannelStatusFunc(const int& loopIndex, const LoopStatus& status);

    virtual int initLoopGroupInfo(LoopGroupInfos& loopGroups);

    void returnToAutoMode() {
        for (LoopSize_t i = 0; i < this->mportCount; ++i) {
            if (LoopStatus::NO_BACKUP_STATUS != mbackupLoopStatusArray[i]) {
                mloopStatusArray[i] = mbackupLoopStatusArray[i];
            }
        }
        changeAutoLoopStatus(mloopStatusArray, this->mportCount);
    }


    bool updateLoopControllerConfig(const LoopControllerConfigInfo& loopControllerConfig) {
        mloopControllerConfig = loopControllerConfig;

        return true;
    }


    LoopControllerConfigInfo mloopControllerConfig;
protected:

    /**
     * 当前回路状态组
     */
    LoopStatus* mloopStatusArray = nullptr;
    LoopStatus* mbackupLoopStatusArray = nullptr;


//    std::string mcommandBuilder;
    //  AcDetector macDetector;
};
